package implementation1.app.commands;

import exceptions.CommandException;
import exceptions.StreamException;
import implementation1.app.Global;
import implementation1.app.InitProcess;
import implementation1.app.streams.AccessAttributes;
import implementation1.data.states.FinishedStatus;
import implementation1.data.states.NewStatus;
import implementation1.data.states.RunningStatus;
import interfaces.app.IProcess;
import interfaces.app.IStream;
import interfaces.app.commands.ICommand;
import interfaces.data.IHandle;

import java.util.ArrayList;
import java.util.ResourceBundle;
import java.util.logging.Level;

/**
 * Abstract class for creating commands.
 * Created 15.10.11
 *
 * @author Jan Šváb
 */
public abstract class Command extends InitProcess implements ICommand
{
    /**
     * Resource of messages.
     */
    protected ResourceBundle bundle = ResourceBundle.getBundle("implementation1.res.commandMessages");

    /**
     * Default constructor.
     *
     * @param parentProcess parent process
     * @param handle        initialization parameters for process
     */
    public Command(IProcess parentProcess, IHandle handle)
    {
        super(handle);
        this.parentProcess = parentProcess;
        this.handle = handle;

        status = new NewStatus();

        threadOfProcess = null;
        openedStreamsOfProcess = new ArrayList<IStream>();
    }


    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p/>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see Thread#run()
     */
    @Override
    public void run()
    {
        status = new RunningStatus();

        try
        {
            mainCommand(handle.getParams());
        } catch (CommandException e)
        {
            writeError(e.getMessage());
        }

        if (threadOfProcess.isInterrupted())
        {
            terminate();
        }
        else if (!(status instanceof FinishedStatus))  //request to quit of process was already did from another process
        {
            if (!quit())
            {
                terminate();
            }
        }

        parentProcess.getChildren().remove(this);
    }

    private void writeError(String msg)
    {
        IStream errorOut = handle.getErrorOut();
        if (errorOut != null)
        {
            try
            {
                errorOut.open(AccessAttributes.WRITE);
                errorOut.writeLine(msg);
            } catch (StreamException e1)
            {
                Global.logger.log(Level.SEVERE, e1.getMessage(), e1);
            } finally
            {
                Global.closeStreamQuietly(errorOut);
            }
        }
    }

    /**
     * Return a command name. (must be the same like class name)
     *
     * @return the command name
     */
    @Override
    public String getCommandName()
    {
        return handle.getCommandName();
    }
}
